#include <iostream>
#include <cstdlib>
#include <string>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>

using namespace std;

int cnt = 0;

void handler(int signo)
{
    cout << "我是一个进程，刚刚获取了一个信号: " << signo << " cnt: " << cnt << endl;
    // exit(1);
}

static void Usage(const std::string &proc)
{
    cerr << "Usage:\n\t" << proc << " signo pid" << endl;
}

static void showPending(sigset_t *pendings)
{
    for (int sig = 1; sig <= 31; sig++)
    {
        if (sigismember(pendings, sig))
        {
            cout << "1";
        }
        else
        {
            cout << "0";
        }
    }
    cout << endl;
}
// 我想写一个kill命令
// mykill 9 1234
int main(int argc, char *argv[])
{
    cout << "pid: " << getpid() << endl;
    // 3. 屏蔽2号信号
    sigset_t bsig, obsig;
    sigemptyset(&bsig);
    sigemptyset(&obsig);
    // sigfillset();
    for (int sig = 1; sig <= 31; sig++)
    {
        // 3.1 添加2号信号到信号屏蔽字中
        sigaddset(&bsig, sig);
        // 2. signal
        signal(sig, handler);
    }
    // 3.2 设置用户级的信号屏蔽字到内核中，让当前进程屏蔽到2号信号
    sigprocmask(SIG_SETMASK, &bsig, &obsig);

    // 1. 不断的获取当前进程的pending信号集
    sigset_t pendings;
    int cnt = 0;
    while (true)
    {
        // 1.1 清空信号集
        sigemptyset(&pendings);
        // 1.2 获取当前进程(谁调用，获取谁)的pending信号集
        if (sigpending(&pendings) == 0)
        {
            // 1.3 打印一下当前进程的pengding信号集
            showPending(&pendings);
        }
        sleep(1);
        cnt++;
        if(cnt == 20)
        {
            cout << "解除对所有信号的block...." << endl;
            sigset_t sigs;
            sigemptyset(&sigs);
            sigaddset(&sigs, 2);
            sigprocmask(SIG_UNBLOCK, &sigs, nullptr);
        }
    }

     //sigset_t
    // cout << "begin ..." << endl;

    // int *p = NULL;
    // *p = 1000;

    // cout << "end ...." << endl;

    // pid_t id = fork();
    // if(id == 0)
    // {
    //     //子进程
    //     // int *p = nullptr;
    //     // *p = 1000; //野指针问题
    //     int a = 10;
    //     a /= 0;
    //     exit(1);
    // }
    // //父进程
    // int status = 0;
    // // nullptr, NULL, 0, '\0' == 0;
    // waitpid(id, &status, 0); // nullptr
    // printf("exitcode: %d, signo: %d, core dump flag: %d\n",
    // (status>>8) & 0xFF, status & 0x7F, (status>>7)&0x1);

    // try
    // {
    //     // throw 10;
    //     // int *p = nullptr;
    //     // *p = 1000;
    //     while (true)
    //     {
    //         int a = 10;
    //         a /= 0;
    //     }

    // }
    // catch (const exception &e)
    // {
    //     // cout << e << endl;
    //     cout << "oops, 我异常啦" << endl;
    //     // sleep(4);
    //     // abort();
    //    cerr << e.what() << endl;
    //     //abort();
    // }
    // while(1)
    // {
    //     cout << "....." << endl;
    // }
    // 崩溃，本质是什么呢？
    // 进程崩溃的本质，是该进程收到了异常信号！
    // C++ try catch
    // 崩溃了，一定会导致进程终止吗？？不一定！
    // 为什么呢？
    // 因为硬件异常，而导致OS向目标进程发送信号，进而导致进程终止的现象！
    // 除零: CPU内部，状态寄存器，当我们出0的时候，CPU内的状态寄存器会被设置成为，有报错：浮点数越界
    //       CPU的内部寄存器(硬件)，OS就会识别到CPU内有报错啦 -> 1. 谁干的？2. 是什么报错(OS->构建信号)
    //       ->目标进程发送信号->目标进程在合适的时候->处理信号->终止进程
    // 越界&&野指针: 我们在语言层面使用的地址(指针), 其实都是虚拟地址->物理地址->物理内存->读取对应的数据和代码的
    //              如果虚拟地址有问题，地址转化的工作是由(MMU(硬件)+页表(软件))， 转化过程就会引起问题->表现在硬件MMU上->OS发现硬件出现了问题
    //              1. 谁干的？2. 是什么报错(OS->构建信号) -> 目标进程发送信号->目标进程在合适的时候->处理信号->终止进程
    // for (int sig = 1; sig <= 31; sig++)
    //     signal(sig, handler);

    // int a[10];
    // a[10000] = 1000;

    // int *p = nullptr;

    // *p = 100;

    //int a=10;
    //a/=0;

    // 统计一个我们的进程1S cnt++多少次
    // signal(SIGALRM, handler);
    // alarm(1);
    // while (1)
    // {
    //     cnt++;
    //     // IO慢不慢呢？？
    //     //printf("hello : %d\n", cnt++);
    // }
    // for(;;)
    // {
    //     // 是谁在推动操作系统做一系列的动作呢？
    //     // 硬件 -- 时钟硬件 -- 给OS发送时钟中断
    //     // CPU主频
    // }
    // signal(2, handler); //没有调用对一个的handler方法，仅仅是注册
    // signal(SIGABRT, handler); //没有调用对一个的handler方法，仅仅是注册

    // while (1)
    // {
    //     sleep(1);
    //     //raise(2);
    //     abort(); //exit() abort();
    // }

    // if(argc != 3)
    // {
    //     Usage(argv[0]);
    //     exit(1);
    // }

    // if(kill(static_cast<pid_t>(atoi(argv[2])), atoi(argv[1])) == -1)
    // {
    //     cerr << "kill: " << strerror(errno) << endl;
    //     exit(2);
    // }

    // 这里不是调用hander方法，这里只是设置了一个回调，让SIGINT(2)产生的时候，该方法才会被调用
    // 如果不产生SIGINT(2)，该方法不会被调用！
    // ctrl + c : 本质就是给前台进程发送2号信号给目标进程，目标进程默认对2号信号的处理，是终止自己
    // 今天更改了对2号信号的处理，设置了用户自定义处理方法
    // for (int sig = 1; sig <= 31; sig++)
    // {
    //     signal(sig, handler); // 设置所有的信号的处理动作，都是自定义动作
    // }
    // signal(2, handler); // 设置所有的信号的处理动作，都是自定义动作
    // sleep(3);
    // cout << "进程已经设置完了" << endl;

    // sleep(3);

    // while (true)
    // {
    //     cout << "我是一个正在运行中的进程: " << getpid() << endl;
    //     sleep(1);
    // }

    // while(1)
    // {
    //    // printf("hello bit\n");
    //     sleep(1);
    // }
    return 0;
}
